
#include <cstdlib>
#include <windows.h>
#include <cstring>
#include <sstream>

#include "ui.h"
#include "engine.h"
#include "conversation.h"
#include "words.h"

#define __SET_AND_RENDER_PANEL(buf, width) \
    ui.SetPanelWidth(width);  \
    ui.SetWordBuffer(buf);  \
    ui.RenderWordPanel();

#define __PANEL_BUFFER_SIZE 30

#define PASS ;

using namespace std;

void Engine::RunTutorial() {
    ui.Dialog(SENTENCES[1], 1);
    ui.Dialog(SENTENCES[2], 1);
    ui.Dialog(SENTENCES[3], 1);
    ui.Dialog(SENTENCES[4], 1);
    ui.Dialog(SENTENCES[5], 1);
    ui.Dialog(SENTENCES[6], 1);

    char ch = ui.AskLetter();
    if (ch == 'E') {
        ui.Dialog(SENTENCES[7], 1);
    } else {
        ui.Dialog(SENTENCES[16], 1);
    }

    ui.Dialog(SENTENCES[8], 1);

    ui.SetWordBuffer("\0\0EE");
    ui.SetPanelWidth(4);
    ui.RenderWordPanel();

    Sleep(2000);

    ui.Dialog(SENTENCES[9], 1);
    ui.Dialog(SENTENCES[10], 1);
    ui.Dialog(SENTENCES[11], 1);

    ui.DrawMan(0);
    Sleep(500);
    ui.DrawMan(1);
    Sleep(500);
    ui.DrawMan(2);
    Sleep(500);
    ui.DrawMan(3);
    Sleep(500);
    ui.DrawMan(4);
    Sleep(500);
    ui.DrawMan(5);
    Sleep(500);
    ui.DrawMan(6);
    Sleep(500);

    ui.Dialog(SENTENCES[12], 1);
    ui.Dialog(SENTENCES[13], 1);


    ui.DrawMan(0);
    Sleep(200);
    ui.DrawMan(6);
    Sleep(200);
    ui.DrawMan(0);
    Sleep(200);
    ui.DrawMan(6);
    Sleep(200);

    ui.Dialog(SENTENCES[14], 1);
    ui.Dialog(SENTENCES[15], 1);

#ifdef USING_CONSOLE_UI

    ui.FadeOff(1);

#endif // USING_CONSOLE_UI
}

char __lower(char ch) {
    if (ch >= 'A' && ch <= 'Z')
        return ch - 'A' + 'a';
    return ch;
}

int __CheckCharAndUpdatePanel(char ch, const char *word, char* panelBuffer) {
    int wLen = strlen(word), count = 0;

    for (int i = 0; i < wLen; ++i) {
        if (__lower(word[i]) == __lower(ch)) {
            panelBuffer[i] = word[i];
            count++;
        }
    }

    int i;
    for (i = 0; i < wLen; ++i)
        if (panelBuffer[i] == 0)
            break;

    if (i == wLen)
        return -1;

    return count;
}

void Engine::RunMainGame() {
    Word word;
    char panelBuffer[__PANEL_BUFFER_SIZE] = {}, ansChar;
    int wLen, count, chance;

    ui.Dialog(SENTENCES[17], 1);

    for (int first = 1;;) {
        ui.ClearAskPanel();

        word = master.GetWord();
        wLen = strlen(word.text);

        memset(panelBuffer, 0, __PANEL_BUFFER_SIZE);

        if (first) {
            first = 0;
            Sleep(250);
            ui.DrawMan(7);
            Sleep(500);
            __SET_AND_RENDER_PANEL(panelBuffer, wLen);
        } else {
            ui.DrawMan(0);
            __SET_AND_RENDER_PANEL(panelBuffer, wLen);
        }

        {
            stringstream ss;
            ss << "the description of this word is: ";
            SegVector sv({
                Segment{ss.str().c_str(), 250},
                Segment{"\"", 0},
                Segment{word.describe, 0},
                Segment{"\"", 100},
                Segment{"", -1},
            });

            ui.Dialog(sv, 1);
        }

        chance = 0;

        for (;;) {
            ansChar = ui.AskLetter();
            count = __CheckCharAndUpdatePanel(ansChar, word.text, panelBuffer);
            if (!count) {
                chance++;
                Sleep(250);
                ui.DrawMan(chance);
                if (chance == 6) {
                    bool again = DoFailure(word.text);
                    if (again)
                        break;
                    goto quit;
                } else {
                    Sleep(150);
                    ui.DrawMan(chance - 1);
                    Sleep(150);
                    ui.DrawMan(chance);
                    Sleep(150);
                    ui.DrawMan(chance - 1);
                    Sleep(150);
                    ui.DrawMan(chance);
                }
            } else if (count == -1) {
                bool again = DoWin(word.text);
                if (again)
                    break;
                goto quit;
            } else {
                Sleep(150);
                __SET_AND_RENDER_PANEL(panelBuffer, wLen);
            }
        }
    }
quit:

#ifdef USING_CONSOLE_UI

    ui.FadeOff(0.5);

#endif // USING_CONSOLE_UI

}

bool Engine::DoWin(const char *word) {

#ifdef USING_CONSOLE_UI

    ui.TwinklePanel();

#endif // USING_CONSOLE_UI

    ui.Dialog(SENTENCES[20], 1);

    bool* ret = (bool*)ui.Dialog(SENTENCES[18], 2);
    bool resp = *ret;
    delete ret;

    return resp;
}


bool Engine::DoFailure(const char *word) {
    Sleep(500);
    ui.DrawMan(7);
    Sleep(500);
    ui.DrawMan(6);
    Sleep(500);
    ui.DrawMan(7);
    Sleep(500);
    ui.DrawMan(6);
    Sleep(1000);

    stringstream ss;
    ss << "You lose, the word is: " << word;

    SegVector sv({Segment{ss.str().c_str(), 100}});

    ui.Dialog(sv, 1);

    bool* ret = (bool*)ui.Dialog(SENTENCES[18], 2);
    bool resp = *ret;
    delete ret;

    return resp;
}

void Engine::ReloadWords() {
    ui.ReloadWords(master.GetGlobalWords());
}

void Engine::StartGame() {
    bool skipTutorial = 1;

    if (first) {
        bool* ret = (bool*)ui.Dialog(SENTENCES[0], 2);
        skipTutorial = *ret;

        delete ret;

        first = 0;
    }

    if (skipTutorial) {
        RunMainGame();
    } else {
        RunTutorial();
        RunMainGame();
    }
}

void Engine::Start() {
    ui.OnStart();
    for (;;) {
        int opt = ui.MainMenu();

        switch (opt) {

        case 0:
            StartGame();
            break;

        case 1:
            ReloadWords();
            break;

        case 2:
            ui.OnExit();
            goto out;

        }
    }
out:
    ;
}
